package com.sheng.leetcode.year2022.month12.day20;

import org.junit.Test;

import java.util.Arrays;

/**
 * @author liusheng
 * @date 2022/12/20
 * <p>
 * 1760. 袋子里最少数目的球<p>
 * <p>
 * 给你一个整数数组 nums ，其中 nums[i] 表示第 i 个袋子里球的数目。同时给你一个整数 maxOperations 。<p>
 * 你可以进行如下操作至多 maxOperations 次：<p>
 * 选择任意一个袋子，并将袋子里的球分到 2 个新的袋子中，每个袋子里都有 正整数 个球。<p>
 * 比方说，一个袋子里有 5 个球，你可以把它们分到两个新袋子里，分别有 1 个和 4 个球，或者分别有 2 个和 3 个球。<p>
 * 你的开销是单个袋子里球数目的 最大值 ，你想要 最小化 开销。<p>
 * 请你返回进行上述操作后的最小开销。<p>
 * <p>
 * 示例 1：<p>
 * 输入：nums = [9], maxOperations = 2<p>
 * 输出：3<p>
 * 解释：<p>
 * - 将装有 9 个球的袋子分成装有 6 个和 3 个球的袋子。[9] -> [6,3] 。<p>
 * - 将装有 6 个球的袋子分成装有 3 个和 3 个球的袋子。[6,3] -> [3,3,3] 。<p>
 * 装有最多球的袋子里装有 3 个球，所以开销为 3 并返回 3 。<p>
 * <p>
 * 示例 2：<p>
 * 输入：nums = [2,4,8,2], maxOperations = 4<p>
 * 输出：2<p>
 * 解释：<p>
 * - 将装有 8 个球的袋子分成装有 4 个和 4 个球的袋子。[2,4,8,2] -> [2,4,4,4,2] 。<p>
 * - 将装有 4 个球的袋子分成装有 2 个和 2 个球的袋子。[2,4,4,4,2] -> [2,2,2,4,4,2] 。<p>
 * - 将装有 4 个球的袋子分成装有 2 个和 2 个球的袋子。[2,2,2,4,4,2] -> [2,2,2,2,2,4,2] 。<p>
 * - 将装有 4 个球的袋子分成装有 2 个和 2 个球的袋子。[2,2,2,2,2,4,2] -> [2,2,2,2,2,2,2,2] 。<p>
 * 装有最多球的袋子里装有 2 个球，所以开销为 2 并返回 2 。<p>
 * <p>
 * 示例 3：<p>
 * 输入：nums = [7,17], maxOperations = 2<p>
 * 输出：7<p>
 * <p>
 * 提示：<p>
 * 1 <= nums.length <= 10^5<p>
 * 1 <= maxOperations, nums[i] <= 10^9<p>
 * <p>
 * 来源：力扣（LeetCode）<p>
 * 链接：<a href="https://leetcode.cn/problems/minimum-limit-of-balls-in-a-bag">1760. 袋子里最少数目的球</a><p>
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。<p>
 */
public class LeetCode1760 {

    @Test
    public void test01() {
        int[] nums = {9};
        int maxOperations = 2;
//        int[] nums = {2, 4, 8, 2};
//        int maxOperations = 4;
//        int[] nums = {7, 17};
//        int maxOperations = 2;
        System.out.println(new Solution().minimumSize(nums, maxOperations));
    }
}

class Solution {
    public int minimumSize(int[] nums, int maxOperations) {
        /**
         * 将袋子里的球进行分割，使得每个袋子装的球的数量尽量减少
         * 在最多操作 maxOperations 次后，袋子中球最多的是多少个
         * 二分查找
         */
        int left = 1, right = Arrays.stream(nums).max().getAsInt();
        int ans = 0;
        while (left <= right) {
            int y = (left + right) / 2;
            long ops = 0;
            for (int x : nums) {
                ops += (x - 1) / y;
            }
            if (ops <= maxOperations) {
                ans = y;
                right = y - 1;
            } else {
                left = y + 1;
            }
        }
        return ans;
    }
}
